#include <TFT_eSPI.h>        // TFT库
#include <SoftwareSerial.h>  // 软件串口库
#include <TinyGPS++.h>       // GPS解析库
#include "ESP8266WiFi.h"     // WIFI库


// 创建TFT对象
TFT_eSPI tft = TFT_eSPI();

// gps模块引脚定义
#define RXPin 4  // GPIO 4 对应nodemcu D2
#define TXPin 5  // GPIO 5 对应nodemcu D1
// 创建软件串口对象用于GPS
SoftwareSerial gpsSerial(RXPin, TXPin);  // RX, TX (根据实际接线调整)

// 创建GPS对象
TinyGPSPlus gps;

// 卫星信息变量
int usedSatellites = 0;  // 实际用于定位的卫星数量
uint32_t lastSatelliteUpdate = 0;

// 变量定义
float currentSpeed = 0.0;       // 当前速度(km/h)
float longitude = 0.0;          // 经度
float latitude = 0.0;           // 纬度
String dateStr = "----/--/--";  // 日期字符串
String timeStr = "--:--:--";    // 时间字符串


void setup() {
  // 初始化串口
  Serial.begin(115200);

  //关闭WIFI模块省电
  WiFi.mode(WIFI_OFF);
  WiFi.forceSleepBegin();

  gpsSerial.begin(9600);

  // 初始化TFT屏幕
  tft.init();
  tft.setRotation(1);         // 根据屏幕方向调整
  tft.fillScreen(TFT_BLACK);  //填充色

  Serial.println("GPS Speedometer Initialized");
}

void loop() {
  // 读取GPS数据
  while (gpsSerial.available() > 0) {
    if (gps.encode(gpsSerial.read())) {
      updateGPSData();
    }
  }

  // 每500ms刷新一次显示
  static uint32_t lastUpdate = 0;
  if (millis() - lastUpdate >= 500) {
    lastUpdate = millis();
    updateDisplay();
  }


  // 每2秒更新一次卫星信息（不需要太频繁）
  if (millis() - lastSatelliteUpdate >= 2000) {
    lastSatelliteUpdate = millis();
    updateSatelliteInfo();
    updateSatelliteDisplay();
  }


  // 如果长时间没有GPS数据，重置GPS对象
  if (millis() > 5000 && gps.charsProcessed() < 10) {
    Serial.println("No GPS data received: check wiring");
    while (true)
      ;
  }
}



// 更新GPS数据
void updateGPSData() {
  // 经纬度
  if (gps.location.isValid()) {
    longitude = gps.location.lng();
    latitude = gps.location.lat();
  }

  // 时速
  if (gps.speed.isValid()) {
    currentSpeed = gps.speed.kmph();
  }

  if (gps.time.isValid() && gps.date.isValid()) {

    // UTC时间转换为北京时间
    // 首先将时间增加8小时
    byte hour = gps.time.hour() + 8;
    byte minute = gps.time.minute();
    byte second = gps.time.second();
    byte day = gps.date.day();
    byte month = gps.date.month();
    int year = gps.date.year();

    // 处理小时超过24的情况
    if (hour >= 24) {
      hour -= 24;
      day++;

      // 检查是否需要增加月份
      if (day > daysInMonth(year, month)) {
        day = 1;
        month++;

        // 检查是否需要增加年份
        if (month > 12) {
          month = 1;
          year++;
        }
      }
    }

    // 格式化时间字符串
    char timeBuffer[12];
    sprintf(timeBuffer, "%02d:%02d:%02d",
            hour,
            minute,
            second);
    timeStr = String(timeBuffer);

    // 格式化日期字符串
    char dateBuffer[12];
    sprintf(dateBuffer, "%02d/%02d/%02d",
            year,
            month,
            day);
    dateStr = String(dateBuffer);
  }
}


// 判断是否为闰年
bool isLeapYear(int year) {
  if (year % 4 != 0) return false;
  if (year % 100 != 0) return true;
  return (year % 400 == 0);
}

// 获取月份的天数（考虑闰年）
byte daysInMonth(int year, byte month) {
  const byte monthDays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  if (month == 2 && isLeapYear(year)) {
    return 29;
  }
  return monthDays[month - 1];
}

// 更新显示
void updateDisplay() {

  // 显示日期和时间
  tft.setTextColor(TFT_CYAN, TFT_BLACK);
  tft.setTextSize(2);
  // 日期
  tft.setCursor(20, 5);
  tft.print(dateStr);
  // 时间
  tft.setCursor(20, 25);
  tft.print(timeStr);

  // 分隔线
  tft.drawFastHLine(0, 50, tft.width(), TFT_DARKGREY);

  // 显示速度
  tft.setTextColor(TFT_GREEN, TFT_BLACK);
  tft.setTextSize(3);
  tft.setCursor(5, 55);
  if (currentSpeed < 100 && currentSpeed >= 10) {
    tft.print(" ");
  }
  if (currentSpeed < 10) {
    tft.print("  ");
  }
  tft.print(currentSpeed, 1);

  tft.setTextSize(2);
  tft.print(" km/h");

  // 分隔线
  tft.drawFastHLine(0, 85, tft.width(), TFT_DARKGREY);

  // 显示经纬度
  tft.setTextColor(TFT_YELLOW, TFT_BLACK);
  tft.setTextSize(1);

  tft.setCursor(20, 95);
  tft.print("Lng:");
  tft.print(longitude, 6);

  tft.setCursor(20, 115);
  tft.print("Lat:");
  tft.print(latitude, 6);
}


void updateSatelliteInfo() {
  // 获取用于定位的卫星数量
  if (gps.satellites.isValid()) {
    usedSatellites = gps.satellites.value();
  } else {
    usedSatellites = 0;  // 无有效数据时显示0
  }
}

void updateSatelliteDisplay() {
  // 清空原有显示区域
  tft.fillRect(120, 95, tft.width(), 20, TFT_BLACK);

  // 显示卫星信息
  tft.setTextColor(TFT_CYAN, TFT_BLACK);
  tft.setTextSize(1);

  // 卫星图标
  tft.drawChar(120, 95, 0x47, TFT_CYAN, TFT_BLACK, 1);  // 卫星符号

  // 使用卫星数量
  tft.setCursor(125, 95);
  tft.print("  ");
  tft.print(usedSatellites);

  // 根据卫星数量显示状态
  tft.fillRect(120, 115, tft.width(), 20, TFT_BLACK);
  tft.setCursor(120, 115);
  if (usedSatellites == 0) {
    tft.setTextColor(TFT_RED, TFT_BLACK);
    tft.print("No Fix");
  } else if (usedSatellites < 4) {
    tft.setTextColor(TFT_YELLOW, TFT_BLACK);
    tft.print("Weak");
  } else {
    tft.setTextColor(TFT_GREEN, TFT_BLACK);
    tft.print("Good");
  }
}
